"""
版本控制服务实现
"""
import hashlib
import json
from typing import List, Dict, Any, Optional
from datetime import datetime
from dataclasses import asdict

from ..models.collaboration_models import Version, Change, ActivityLog


class VersionControlService:
    """版本控制服务"""
    
    def __init__(self):
        self.versions: Dict[str, List[Version]] = {}  # project_id -> versions
        self.activity_logs: Dict[str, ActivityLog] = {}
        
    async def save_version(self, project_id: str, changes: List[Change], 
                          author_id: str, commit_message: str = "") -> Version:
        """保存新版本"""
        try:
            # 获取当前版本号
            current_version_number = await self._get_latest_version_number(project_id)
            new_version_number = current_version_number + 1
            
            # 生成版本ID
            version_id = f"v{new_version_number}_{project_id}_{datetime.now().timestamp()}"
            
            # 计算内容哈希
            content_hash = await self._calculate_content_hash(changes)
            
            # 获取父版本ID
            parent_version_id = None
            if project_id in self.versions and self.versions[project_id]:
                parent_version_id = self.versions[project_id][-1].version_id
            
            # 创建新版本
            new_version = Version(
                version_id=version_id,
                project_id=project_id,
                version_number=new_version_number,
                timestamp=datetime.now(),
                author_id=author_id,
                changes=changes.copy(),
                commit_message=commit_message or f"版本 {new_version_number}",
                parent_version_id=parent_version_id,
                content_hash=content_hash
            )
            
            # 保存版本
            if project_id not in self.versions:
                self.versions[project_id] = []
            self.versions[project_id].append(new_version)
            
            # 记录活动日志
            await self._log_version_activity(project_id, author_id, "version_saved", {
                "version_id": version_id,
                "version_number": new_version_number,
                "changes_count": len(changes)
            })
            
            return new_version
            
        except Exception as e:
            print(f"保存版本失败: {e}")
            raise
    
    async def get_version_history(self, project_id: str, limit: int = 50) -> List[Version]:
        """获取版本历史"""
        if project_id not in self.versions:
            return []
        
        versions = self.versions[project_id]
        # 按时间倒序返回最近的版本
        return sorted(versions, key=lambda x: x.timestamp, reverse=True)[:limit]
    
    async def get_version_by_id(self, project_id: str, version_id: str) -> Optional[Version]:
        """根据ID获取特定版本"""
        if project_id not in self.versions:
            return None
        
        for version in self.versions[project_id]:
            if version.version_id == version_id:
                return version
        
        return None
    
    async def rollback_to_version(self, project_id: str, version_id: str, 
                                 user_id: str) -> bool:
        """回滚到指定版本"""
        try:
            target_version = await self.get_version_by_id(project_id, version_id)
            if not target_version:
                return False
            
            # 创建回滚版本
            rollback_changes = await self._create_rollback_changes(target_version)
            
            rollback_version = await self.save_version(
                project_id=project_id,
                changes=rollback_changes,
                author_id=user_id,
                commit_message=f"回滚到版本 {target_version.version_number}"
            )
            
            # 记录回滚活动
            await self._log_version_activity(project_id, user_id, "version_rollback", {
                "target_version_id": version_id,
                "rollback_version_id": rollback_version.version_id
            })
            
            return True
            
        except Exception as e:
            print(f"版本回滚失败: {e}")
            return False
    
    async def compare_versions(self, project_id: str, version1_id: str, 
                             version2_id: str) -> Dict[str, Any]:
        """比较两个版本的差异"""
        version1 = await self.get_version_by_id(project_id, version1_id)
        version2 = await self.get_version_by_id(project_id, version2_id)
        
        if not version1 or not version2:
            return {"error": "版本不存在"}
        
        comparison = {
            "version1": {
                "id": version1.version_id,
                "number": version1.version_number,
                "timestamp": version1.timestamp.isoformat(),
                "author": version1.author_id,
                "changes_count": len(version1.changes)
            },
            "version2": {
                "id": version2.version_id,
                "number": version2.version_number,
                "timestamp": version2.timestamp.isoformat(),
                "author": version2.author_id,
                "changes_count": len(version2.changes)
            },
            "differences": await self._calculate_differences(version1, version2)
        }
        
        return comparison
    
    async def get_changes_between_versions(self, project_id: str, 
                                         from_version_id: str, 
                                         to_version_id: str) -> List[Change]:
        """获取两个版本之间的所有变更"""
        from_version = await self.get_version_by_id(project_id, from_version_id)
        to_version = await self.get_version_by_id(project_id, to_version_id)
        
        if not from_version or not to_version:
            return []
        
        # 获取版本范围内的所有变更
        all_versions = self.versions.get(project_id, [])
        
        # 按版本号排序
        sorted_versions = sorted(all_versions, key=lambda x: x.version_number)
        
        changes = []
        collecting = False
        
        for version in sorted_versions:
            if version.version_id == from_version_id:
                collecting = True
                continue
            
            if collecting:
                changes.extend(version.changes)
                
            if version.version_id == to_version_id:
                break
        
        return changes
    
    async def generate_activity_log(self, project_id: str, 
                                  start_date: Optional[datetime] = None,
                                  end_date: Optional[datetime] = None) -> ActivityLog:
        """生成活动日志"""
        if project_id not in self.activity_logs:
            self.activity_logs[project_id] = ActivityLog(
                project_id=project_id,
                activities=[],
                start_date=start_date or datetime.now(),
                end_date=end_date or datetime.now(),
                total_activities=0
            )
        
        log = self.activity_logs[project_id]
        
        # 过滤日期范围内的活动
        if start_date or end_date:
            filtered_activities = []
            for activity in log.activities:
                activity_time = activity["timestamp"]
                if isinstance(activity_time, str):
                    activity_time = datetime.fromisoformat(activity_time)
                
                if start_date and activity_time < start_date:
                    continue
                if end_date and activity_time > end_date:
                    continue
                
                filtered_activities.append(activity)
            
            return ActivityLog(
                project_id=project_id,
                activities=filtered_activities,
                start_date=start_date or log.start_date,
                end_date=end_date or log.end_date,
                total_activities=len(filtered_activities)
            )
        
        return log
    
    async def _get_latest_version_number(self, project_id: str) -> int:
        """获取最新版本号"""
        if project_id not in self.versions or not self.versions[project_id]:
            return 0
        
        return max(version.version_number for version in self.versions[project_id])
    
    async def _calculate_content_hash(self, changes: List[Change]) -> str:
        """计算内容哈希"""
        content_str = json.dumps([asdict(change) for change in changes], 
                                sort_keys=True, default=str)
        return hashlib.sha256(content_str.encode()).hexdigest()
    
    async def _create_rollback_changes(self, target_version: Version) -> List[Change]:
        """创建回滚变更"""
        # 简化实现：直接使用目标版本的变更
        # 在实际应用中，这里需要更复杂的逻辑来生成反向变更
        return target_version.changes.copy()
    
    async def _calculate_differences(self, version1: Version, version2: Version) -> List[Dict[str, Any]]:
        """计算版本差异"""
        differences = []
        
        # 比较变更数量
        if len(version1.changes) != len(version2.changes):
            differences.append({
                "type": "changes_count",
                "version1_count": len(version1.changes),
                "version2_count": len(version2.changes)
            })
        
        # 比较内容哈希
        if version1.content_hash != version2.content_hash:
            differences.append({
                "type": "content_hash",
                "version1_hash": version1.content_hash,
                "version2_hash": version2.content_hash
            })
        
        # 比较作者
        if version1.author_id != version2.author_id:
            differences.append({
                "type": "author",
                "version1_author": version1.author_id,
                "version2_author": version2.author_id
            })
        
        return differences
    
    async def _log_version_activity(self, project_id: str, user_id: str, 
                                   action: str, details: Dict[str, Any]):
        """记录版本活动"""
        if project_id not in self.activity_logs:
            self.activity_logs[project_id] = ActivityLog(
                project_id=project_id,
                activities=[],
                start_date=datetime.now(),
                end_date=datetime.now(),
                total_activities=0
            )
        
        log = self.activity_logs[project_id]
        log.add_activity(user_id, action, details)
        log.end_date = datetime.now()
    
    async def create_branch(self, project_id: str, branch_name: str, 
                           from_version_id: str, user_id: str) -> bool:
        """创建分支（简化实现）"""
        try:
            base_version = await self.get_version_by_id(project_id, from_version_id)
            if not base_version:
                return False
            
            # 在实际应用中，这里需要更复杂的分支管理逻辑
            branch_project_id = f"{project_id}_branch_{branch_name}"
            
            # 复制基础版本到新分支
            branch_version = Version(
                version_id=f"v1_{branch_project_id}_{datetime.now().timestamp()}",
                project_id=branch_project_id,
                version_number=1,
                timestamp=datetime.now(),
                author_id=user_id,
                changes=base_version.changes.copy(),
                commit_message=f"从版本 {base_version.version_number} 创建分支 {branch_name}",
                parent_version_id=base_version.version_id
            )
            
            if branch_project_id not in self.versions:
                self.versions[branch_project_id] = []
            self.versions[branch_project_id].append(branch_version)
            
            await self._log_version_activity(project_id, user_id, "branch_created", {
                "branch_name": branch_name,
                "base_version_id": from_version_id,
                "branch_project_id": branch_project_id
            })
            
            return True
            
        except Exception as e:
            print(f"创建分支失败: {e}")
            return False
    
    async def merge_branch(self, main_project_id: str, branch_project_id: str, 
                          user_id: str) -> bool:
        """合并分支（简化实现）"""
        try:
            if branch_project_id not in self.versions:
                return False
            
            branch_versions = self.versions[branch_project_id]
            if not branch_versions:
                return False
            
            # 获取分支的最新版本
            latest_branch_version = max(branch_versions, key=lambda x: x.version_number)
            
            # 将分支变更合并到主分支
            merged_version = await self.save_version(
                project_id=main_project_id,
                changes=latest_branch_version.changes,
                author_id=user_id,
                commit_message=f"合并分支 {branch_project_id}"
            )
            
            await self._log_version_activity(main_project_id, user_id, "branch_merged", {
                "branch_project_id": branch_project_id,
                "merged_version_id": merged_version.version_id
            })
            
            return True
            
        except Exception as e:
            print(f"合并分支失败: {e}")
            return False